package motor;

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

import modele.Graphe;

import utils.*;
import surface.*;

/**
 * Very simple applet to handle fundamentals of A.I. in games.
 * 
 * This is the main applet, it handles a "battle field" with objects on it,
 * Every frames the whole field is paint again, there is a (simple) GUI.
 * 
 * How it works? After initialization of Surface, Bots, ... the 
 * applet enters (in run()) an infinite loop that... just sleep to wait for next frame,
 * and then call updateBots(), then updateBelettes() then repaint().
 * The first and second calls update positions and animations of bots and bullets,
 * the last one simple repaint all the field from scratch.
 * 
 * You may want to extend this applet using openGL like JOGL in order to enter the third dimension
 * A very simple entry for this would be for instance http://jsolutions.se/DukeBeanEm
 * 
 * @author L. Simon, Univ. Paris Sud, 2008
 *
 */

public class BattleField extends Applet implements Runnable, MouseListener, MouseMotionListener, KeyListener
{
	private static final long serialVersionUID = 1L;

	Surface surface; // The surface that contains the objects...

	// Those constants are hard constants... Why? I don't know.
	static final public float MAXX = 10000F; // Size of the battlefield, in float (not pixels)
	static final public float MAXY = 7500F;

	static final public int PREF_VIEWER_XSIZE = 800; // size in pixels (in x, the y is automatically deduced)

	// Viewer variables
	float viewer_scale; // Ratio from size of surface to size of viewer
	static public int viewer_xsize;
	static public int viewer_ysize;

	// Canvas for double buffering
	Image buffer_canvasimage;
	Graphics buffer_canvas; // Where to draw (off-screen buffer)
	Graphics viewer_canvas; // What the user actually see (on-screen buffer)


	/**
	 * Thread that sleeps and update the screen.
	 */
	private Thread update;

	private Motor motor;

	// Very simple constructor
	public BattleField()
	{
		viewer_scale = MAXX/PREF_VIEWER_XSIZE;
	}

	public void init()
	{
		super.init();

		viewer_xsize = PREF_VIEWER_XSIZE; // size in pixels
		viewer_ysize = (int)(MAXY/viewer_scale); // The y axe is automatically computed

		resize(viewer_xsize, viewer_ysize);
		buffer_canvasimage = createImage(viewer_xsize, viewer_ysize);
		buffer_canvas = buffer_canvasimage.getGraphics();
		viewer_canvas = this.getGraphics();

		addMouseListener(this);
		addMouseMotionListener(this);
		addKeyListener(this);

		initSurface();
	}


	/**
	 * Called ones to init the surface. This is where
	 * all objects attached to the surface should be loaded.
	 * Dynamic objects like bots and bullet are handled elsewhere.
	 */
	public void initSurface()
	{
		surface = new Surface(viewer_xsize,viewer_ysize,viewer_scale);
		
		motor = new Motor( surface );
	}

	public boolean handleEvent(Event event)
	{
		boolean returnValue = false;
		return returnValue;
	}

	public void start()
	{
		if(update == null)
		{
			update = new Thread(this);
			update.start();
		}
	}

	public void stop()
	{
		update = null;
	}

	/* 
	 * This is the main loop of the game. Sleeping, then updating positions then redrawing
	 * If you want a constant framerate, you should measure how much you'll have to sleep
	 * depending on the time eated by updates functions.
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run()
	{
		do
		{
			motor.goOn();

			repaint();
			try
			{
				Thread.sleep(33);
			}
			catch(InterruptedException _ex) { }
		} while(true);
	}

	// Use very simple double buffering technique...
	/**
	 * This is a very simple double buffering technique.
	 * Drawing are done offscreen, in the buffer_canvasimage canvas.
	 * Ones all drawings are done, we copy the whole canvas to 
	 * the actual viewed canvas, viewer_canvas.
	 * Thus the player will only see a very fast update of its window.
	 * No flickering.
	 * 
	 */
	private void showbuffer()
	{
		viewer_canvas.drawImage(buffer_canvasimage, 0, 0, this);
	}

	/* 
	 * Called by repaint, to paint all the offscreen surface.
	 * We erase everything, then redraw each components.
	 * 
	 * @see java.awt.Container#paint(java.awt.Graphics)
	 */
	public void paint(Graphics g)
	{
		// 1. We erase everything
		buffer_canvas.setColor(Color.lightGray); // Background color
		buffer_canvas.fillRect(0, 0, viewer_xsize, viewer_ysize);

		// 2. We draw the surface (and its objects)
		surface.draw(buffer_canvas);

		motor.draw( buffer_canvas );
	
		drawHUD();
		showbuffer();
	}


	/**
	 * string printed in the simple hud. For debugging...
	 */
	String gui_string = "";
	/**
	 * Very simple GUI.. Just print the infos string on the bottom of the screen, in a rectangle.
	 */
	private void drawHUD() {
		buffer_canvas.setColor(Color.red);
		buffer_canvas.drawRect(20,viewer_ysize-23,viewer_xsize-41,20);
		buffer_canvas.drawChars(gui_string.toCharArray(), 0, Math.min(80,gui_string.length()), 22, viewer_ysize-7);
	}

	// Simply repaint the battle field... Called every frame...
	public void update(Graphics g)
	{
		paint(g);
	}



	public static void main(String args[])
	{
		Frame f = new Frame();
		BattleField app = new BattleField();
		app.init();
		app.start();
		f.add("Center", app);
	}


	// Two point2D to memorize mouse gestures (pointA first click, pointB second click)
	private Vector2d pointA = new Vector2d(-1,-1);
	private Vector2d pointB = new Vector2d(-1,-1);
	
	private Vector2d pointC = new Vector2d(-1,-1);
	private Vector2d pointD = new Vector2d(-1,-1);
	//private Vector2d pointB = new Vector2d(-1,-1);


	// Those methods have to be there... Even if they are empty.
	public void mouseClicked(MouseEvent e)
	{

	}
	
	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
	
	
	public void mousePressed(MouseEvent e)
	{
		pointC.x = e.getX();
		pointC.y = e.getY();	

	}
	
	public void mouseDragged(MouseEvent e)
	{
		pointD.x = e.getX();
		pointD.y = e.getY();	
	
	}


	/* Here we memorize the mouse position to draw lines where points can see eachother.
	 * TODO: you must handle mouse events in your game.
	 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	public void mouseReleased(MouseEvent e)
	{

	}

	/* TODO: use this method your own way.
	 * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
	 */
	public void mouseMoved(MouseEvent e)
	{
		if (pointA.x > -1)
		{ // pointA has been defined
			pointB.x = e.getX();
			pointB.y = e.getY();
		}
	}

	@Override
	public void keyPressed(KeyEvent arg0)
	{
		// TODO Auto-generated method stub
	}

	@Override
	public void keyReleased(KeyEvent arg0)
	{
		// TODO Auto-generated method stub
		
	}

	public void keyTyped(KeyEvent arg0)
	{

	}
}
